import {extend, isObject} from '../base'
const pathToRegexp = require('path-to-regexp');

var globalObj = typeof window === 'undefined' ? global : window ;

import fetchFun from "./fetch";
var orginFetch = fetchFun();
// var orginFetch = globalObj.fetch;

// if (!Promise) {
//     Promise = require('promise-polyfill')
// } else if (!Promise.finally) {
//     Promise.finally = require('promise-polyfill').finally
// }

//存储 mock 相关信息
var _fetch_mock = [];

var _fetchResponse = function (mockResult) {
    var response = new globalObj.Response(undefined,{status : 200});
    // response.status = 200;
    response.text = function () {
        if(mockResult.result instanceof Promise){
            return response.text;
        }
        return new Promise((resolve) => {
            //把结果转换为 json 字符串
            resolve(JSON.stringify(mockResult.result));
        })
    }

    //把 mock 时的 config.headers 值写入到时 response.headers 中
    for(var key in mockResult.config.headers){
        response.headers.append(key.toLowerCase(), mockResult.config.headers[key]);
    }

    return response;

}

export var fetch = async function (url, options) {

    let config = {...options, url};
    let mockResult = await _mockRequest(config);
    if(mockResult){
        var response = undefined;
        if(mockResult.result instanceof globalObj.Response){
            response = mockResult.result;
        }else{
            response = _fetchResponse(mockResult);
        }
        // {text:mockResult.result}
        return new Promise((resolve) => {
            resolve(response);
        })
    }
    return orginFetch(url, options)
}

var _mockRequest = async function (request) {

    var method = request.method || '';

    for (var n = 0; n < _fetch_mock.length; n++) {

        var item = _fetch_mock[n];

        if (item && item.method && item.method != method) {
            //如果请求 method 不匹配
            continue;
        }

        var config = item.config;
        var url = request.url.indexOf('?') != -1 ?
          request.url.substr(0, request.url.indexOf('?')) : request.url

        var m = item.requestMatche(url);

        if (!m) {//如果没有匹配成功
            continue;
        }

        if (typeof config.data == 'function') {
            var r = config.data(request);
            if (r !== undefined) {

                if(r instanceof Promise){
                    r = await r;
                }
                //如果返回结果
                return {result: r, config: config};
            }
            //无返回结果，表示对当前请求不进行 mock ，继续下一个
            continue;
        } else {
            //如果 mock 结果为 null 或 undefined ,也能够判断出来
            return {result: config.data, config: config}
        }

    }

}

/**
 *
 * 接受三个格式参数
 * 第一种：mock(url,data) 对指定的 url 返回 data 数据
 * 第二种：mock(url,fun) 对指定的 url 调用 fun
 * 第三种：mock({
 *     url:'', //要模拟的url
 *     method: '', //要模拟的 http 请求方法，post 或 get，无此参数表示都模拟
 *     data: function(){} || {...},   //对应的 url 返回的数据,对应的 url 调用此函数
 *     headers: {},
 *  })
 * 当 data 和 function 两个参数同时有时，只会调用 function，忽略掉 data 参数
 *
 * 第一种和第二种调用方式是第三种的一个特例
 *
 *
 * 如果要模拟 error ，只能在 function 中抛出异常，抛出的数据格式与 http 请求错误一样
 *
 */
fetch.mock = (url,data) => {

    var config = undefined;
    //
    if(url instanceof RegExp || typeof url == 'function' || typeof url == 'string'){
        config = {
            url:url,
        }
        config.data = data;

    }else{
        config = extend(url);
    }

    config.headers = config.headers || {};
    //设置请求响应头中 content-type 的默认值为 application/json
    config.headers["content-type"] = config.headers["content-type"] || 'application/json';

    var requestMatche = requestMatches(config.url);
    _fetch_mock.push({
        config:config,
        requestMatche:requestMatche,
    });
}

function requestMatches(urlOrPredicate) {
    if (typeof urlOrPredicate === 'function') {
        return urlOrPredicate
    }

    //pathToRegexp
    const reg =
      urlOrPredicate instanceof RegExp
        ? urlOrPredicate
        : pathToRegexp(urlOrPredicate)

    // urlOrPredicate.exec(input)
    return input => {
        const requestUrl = typeof input === 'object' ? input.url : input
        return reg.exec(requestUrl) !== null
    }
}

fetch.resetMocks = () => {
    //置空 mock 信息
    _fetch_mock = [];
}

//启用 fetch mock 功能
fetch.enableMocks = () => {
    globalObj.fetch = fetch;
    fetch.resetMocks();
}

/**
 * 清除 url 对应的 http 请求模拟设置
 */
fetch.removeMock = (url) => {
    _fetch_mock = this._fetch_mock.filter(item => item.config.url != url);
}

//禁用 fetch mock 功能
fetch.disableMocks = () => {
    globalObj.fetch = orginFetch;
    fetch.resetMocks();
}
